/**
 * @program: HelpLuojia
 * @description: 地图基本操作service实现类
 * @author: PXM
 * @create: 2022-11-21 19:18
 **/
package com.whu.helpluojia.service.impl;

import com.whu.helpluojia.domain.*;
import com.whu.helpluojia.service.*;
import com.whu.helpluojia.util.DistanceUil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.time.Period;
import java.time.ZoneId;
import java.util.*;

@Slf4j
@Service
public class MapServiceImpl implements MapService {

    @Autowired
    LostAndFoundService lostAndFoundService;

    @Autowired
    SupplyService supplyService;

    @Autowired
    FindService findService;

    @Autowired
    BagManService bagManService;

    List<Object> res = new ArrayList<>();

    @Override
    public List<HelpInformation> search(String type, String description, String date, double x, double y,int distance) throws InstantiationException, IllegalAccessException {

        res.clear();

        if (Objects.equals(type, "")) {
            return null;
        } else{
            laf(type);
            if(!Objects.equals(description, "")) {
                description(description,type);
            }
            if(!Objects.equals(date, "")){
                recent(date,type);
            }
            if(distance != 0 && x != 0 && y != 0){
                location(x,y,distance,type);
            }
            return abstractHelp(type);
        }

        //return res;
    }

    public List<HelpInformation> abstractHelp(String type){
        if(Objects.equals(type, "失物招领")){
            List<HelpInformation> helpInformations = new ArrayList<>();
            for(int i = 0;i < res.size();i++){
                helpInformations.add(new HelpInformation());
                LostAndFound lostAndFound = (LostAndFound)res.get(i);
                helpInformations.get(i).setId(lostAndFound.getId());
                helpInformations.get(i).setType(lostAndFound.getType());
                helpInformations.get(i).setLat(lostAndFound.getLat());
                helpInformations.get(i).setLon(lostAndFound.getLon());
            }
            //res.addAll(Arrays.asList(helpInformations));
            return helpInformations;
        } else if (Objects.equals(type, "物品供需")) {
            List<HelpInformation> helpInformations = new ArrayList<>();
            for(int i = 0;i < res.size();i++){
                helpInformations.add(new HelpInformation());
                Supply supply = (Supply) res.get(i);
                helpInformations.get(i).setId(supply.getId());
                helpInformations.get(i).setType(supply.getType());
                helpInformations.get(i).setLat(supply.getLat());
                helpInformations.get(i).setLon(supply.getLon());
            }
            return helpInformations;
        } else if (Objects.equals(type, "寻物启事")) {
            List<HelpInformation> helpInformations = new ArrayList<>();
            for(int i = 0;i < res.size();i++){
                helpInformations.add(new HelpInformation());
                Find find = (Find)res.get(i);
                helpInformations.get(i).setId(find.getId());
                helpInformations.get(i).setType(find.getType());
                helpInformations.get(i).setLat((find.getLatMax() + find.getLatMin()) / 2.0);
                helpInformations.get(i).setLon((find.getLonMax() + find.getLonMin()) / 2.0);
            }
            return helpInformations;
        } else if (Objects.equals(type, "求跑腿")) {
            List<HelpInformation> helpInformations = new ArrayList<>();
            for(int i = 0;i < res.size();i++){
                helpInformations.add(new HelpInformation());
                Bagman bagMan = (Bagman)res.get(i);
                helpInformations.get(i).setId(bagMan.getId());
                helpInformations.get(i).setType(bagMan.getType());
                helpInformations.get(i).setLat(bagMan.getStartLat());
                helpInformations.get(i).setLon(bagMan.getStartLon());
            }
            return helpInformations;
        }
        return new ArrayList<>();
    }

    public void laf(String type){
        if(Objects.equals(type, "失物招领")){
            LostAndFound[] lostAndFounds = lostAndFoundService.selectAll();
            res.addAll(Arrays.asList(lostAndFounds));
        } else if (Objects.equals(type, "物品供需")) {
            Supply[] supplies = supplyService.selectAll();
            res.addAll(Arrays.asList(supplies));
        } else if (Objects.equals(type, "寻物启事")) {
            Find[] finds = findService.selectAll();
            res.addAll(Arrays.asList(finds));
        } else if (Objects.equals(type, "求跑腿")) {
            Bagman[] bagMen = bagManService.selectAll();
            res.addAll(Arrays.asList(bagMen));
        }
    }


    //模糊查询
    public void description(String description,String type){
        //定义全局阈值
        double threshold = 0.5;
        if(Objects.equals(type, "失物招领")){
            for(int i = 0; i < res.size(); i++){
                LostAndFound lostAndFound = (LostAndFound)res.get(i);
                if(!isSame(description,lostAndFound.getDescription(),threshold,new String[0]) ||
                        !isSame(description,lostAndFound.getType(),threshold,new String[0])){
                    res.remove(lostAndFound);
                }
            }
        }
        if(Objects.equals(type, "物品供需")){
            for(int i = 0; i < res.size(); i++){
                Supply supply = (Supply) res.get(i);
                if(!isSame(description,supply.getType(),threshold,new String[0])){
                    res.remove(supply);
                }
            }
        }
        if(Objects.equals(type, "寻物启事")){
            for(int i = 0; i < res.size(); i++){
                Find find = (Find)res.get(i);
                if(!isSame(description,find.getDescription(),threshold,new String[0]) ||
                        !isSame(description,find.getType(),threshold,new String[0])){
                    res.remove(find);
                }
            }
        }
        if(Objects.equals(type, "求跑腿")){
            for(int i = 0; i < res.size(); i++){
                Bagman bagMan = (Bagman)res.get(i);
                if(!isSame(description,bagMan.getDescription(),threshold,new String[0]) ||
                        !isSame(description,bagMan.getType(),threshold,new String[0])){
                    res.remove(bagMan);
                }
            }
        }
    }

    /**
     *
     * @param str1 待比较字符串1
     * @param str2 待比较字符串2
     * @param threshold 比较阈值
     * @param redundances 冗余信息项
     * @return boolean
     */
    public static boolean isSame(String str1, String str2, double threshold, String[] redundances) {
        if (str1 == null || str2 == null || str1.length() == 0 || str2.length() == 0)
            throw new NullPointerException("str1 or str2 is null");
        str1 = deleteRedundances(str1, redundances);
        str2 = deleteRedundances(str2, redundances);
        int length = Math.max(str1.length(), str2.length());
        return isSame(str1, str2, length, threshold);
    }

    //比较重合率与阈值
    public static boolean isSame(String str1, String str2, int length, double threshold) {
        //得到重合率
        double re = coincidenceRate(str1, str2, length);
        return re >= threshold;
    }

    //计算重合率
    private static double coincidenceRate(String str1, String str2, int length) {
        int coincidenc = longestCommonSubsequence(str1, str2);
        //return MathUtils.txfloat(coincidenc, length);
        //coincidenc % length => 最长公共子序列的长度 % 较短字符串的长度 => 描述两个字符串的匹配度
        return coincidenc % length;
    }

    //去处冗余
    private static String deleteRedundances(String str, String[] redundances) {
        StringBuilder stringBuilder = new StringBuilder(str);
        for (String redundance : redundances) {
            int index = stringBuilder.indexOf(redundance);
            if (index != -1) stringBuilder.replace(index, index + redundance.length(), "");
        }
        return stringBuilder.toString();
    }

    //最长公共子序列算法
    public static int longestCommonSubsequence(String str1, String str2) {
        if (str1 == null || str2 == null) return 0;
        int m = str1.length(), n = str2.length();
        int[][] cache = new int[m + 1][n + 1];
        for (int i = m - 1; i >= 0; i--) {
            for (int j = n - 1; j >= 0; j--) {
                if (str1.charAt(i) == str2.charAt(j)) cache[i][j] = cache[i + 1][j + 1] + 1;
                else cache[i][j] = Math.max(cache[i][j + 1], cache[i + 1][j]);
            }
        }
        return cache[0][0];
    }

    //天数
    public void recent(String datelimit,String type) throws InstantiationException, IllegalAccessException {
        LocalDate now = LocalDate.now();//获取当前时间
        if(Objects.equals(type, "失物招领")){
            //List<LostAndFound> lostAndFoundList = res.stream().map().collect(Collectors.toList());
            for(int i = 0; i < res.size(); i++){
                LostAndFound lostAndFound = (LostAndFound)res.get(i);
                Date date = lostAndFound.getTime();
                //Date转LocalDate
                LocalDate old = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
                Period period = Period.between(old,now);
                if((datelimit == "最近三天" && period.getDays() > 3) ||
                        (datelimit == "最近五天" && period.getDays() > 5) ||
                        (datelimit == "最近七天" && period.getDays() > 7) ||
                        (datelimit == "今日内" && period.getDays() > 1)) {
                    res.remove(lostAndFound);
                }
            }
        }
        if(Objects.equals(type, "物品供需")){
            //List<LostAndFound> lostAndFoundList = res.stream().map().collect(Collectors.toList());
            for(int i = 0; i < res.size(); i++){
                Supply supply = (Supply) res.get(i);
                Date date = supply.getTime();
                //Date转LocalDate
                LocalDate old = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
                Period period = Period.between(old,now);
                if((datelimit == "最近三天" && period.getDays() > 3) ||
                        (datelimit == "最近五天" && period.getDays() > 5) ||
                        (datelimit == "最近七天" && period.getDays() > 7) ||
                        (datelimit == "今日内" && period.getDays() > 1)) {
                    res.remove(supply);
                }
            }
        }
        if(Objects.equals(type, "寻物启事")){
            //List<LostAndFound> lostAndFoundList = res.stream().map().collect(Collectors.toList());
            for(int i = 0; i < res.size(); i++){
                Find find = (Find)res.get(i);
                Date date = find.getTime();
                //Date转LocalDate
                LocalDate old = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
                Period period = Period.between(old,now);
                if((datelimit == "最近三天" && period.getDays() > 3) ||
                        (datelimit == "最近五天" && period.getDays() > 5) ||
                        (datelimit == "最近七天" && period.getDays() > 7) ||
                        (datelimit == "今日内" && period.getDays() > 1)) {
                    res.remove(find);
                }
            }
        }
        if(Objects.equals(type, "求跑腿")){
            //List<LostAndFound> lostAndFoundList = res.stream().map().collect(Collectors.toList());
            for(int i = 0; i < res.size(); i++){
                Bagman bagMan = (Bagman)res.get(i);
                Date date = bagMan.getTime();
                //Date转LocalDate
                LocalDate old = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
                Period period = Period.between(old,now);
                if((datelimit == "最近三天" && period.getDays() > 3) ||
                        (datelimit == "最近五天" && period.getDays() > 5) ||
                        (datelimit == "最近七天" && period.getDays() > 7) ||
                        (datelimit == "今日内" && period.getDays() > 1)) {
                    res.remove(bagMan);
                }
            }
        }
    }

    //范围查找
    public void location(double x,double y,int distance,String type){
        /*double temp1 = x * x + y * y;*/
        if(Objects.equals(type, "失物招领")){
            for(int i = 0; i < res.size(); i++){
                LostAndFound lostAndFound = (LostAndFound)res.get(i);
                double lat = lostAndFound.getLat();//纬度
                double lon = lostAndFound.getLon();//经度
                double distanceCaculate= DistanceUil.getDistance(x,y,lon,lat);
                log.info("距离"+String.valueOf(distanceCaculate));
                if(distanceCaculate>distance){
                    res.remove(lostAndFound);
                }
            }
        }
        if(Objects.equals(type, "物品供需")){
            for(int i = 0; i < res.size(); i++){
                Supply supply = (Supply) res.get(i);
                double lat = supply.getLat();//纬度
                double lon = supply.getLon();//经度
                double distanceCaculate= DistanceUil.getDistance(x,y,lon,lat);
                if(distanceCaculate>distance){
                    res.remove(supply);
                }
            }
        }
        if(Objects.equals(type, "寻物启事")){
            for(int i = 0; i < res.size(); i++){
                Find find = (Find)res.get(i);
                double lat = (find.getLatMax() + find.getLatMin()) / 2.0;
                double lon = (find.getLonMax() + find.getLonMin()) / 2.0;
                double distanceCaculate= DistanceUil.getDistance(x,y,lon,lat);
                if(distanceCaculate>distance){
                    res.remove(find);
                }
            }
        }
        if(Objects.equals(type, "求跑腿")){
            for(int i = 0; i < res.size(); i++){
                Bagman bagMan = (Bagman) res.get(i);
                double lat = bagMan.getStartLat();//起点纬度
                double lon = bagMan.getStartLon();//经度
                double distanceCaculate= DistanceUil.getDistance(x,y,lon,lat);
                if(distanceCaculate>distance){
                    res.remove(bagMan);
                }
            }
        }
    }
}
